package core

import (
	"errors"
	"fmt"
	"strings"
	"time"
	crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
	"github.com/OpenBazaar/jsonpb"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/wallet-interface"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/incubator/datastructure"
	"math/big"
	"io/ioutil"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/OpenBazaar/openbazaar-go/incubator/contracts"
	"github.com/OpenBazaar/openbazaar-go/incubator"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"path"
	"strconv"
	"math/rand"
	"encoding/json"
)

func Purchase(n *core.OpenBazaarNode, data *core.PurchaseData) (orderId *big.Int, paymentAddress string, paymentAmount uint64, err error) {
	contract, err := createContractWithOrder(*n, data)
	if err != nil {
		return nil, "", 0, err
	}
	//Get Vendor Wallet address
	total, totalItem, totalShipping,VendorWalletAddress, err := CalculateOrderTotal(n, contract)
	fmt.Println("Vendorwalletaddress:",VendorWalletAddress)
	if err != nil {
		return nil, "", 0, err
	}
	//Get listings and vendor peerID
	vendorID := contract.VendorListings[0].VendorID.PeerID
	orderId, error := CalcOrderId(n, contract.BuyerOrder)
	if error != nil {
		return nil, "", 0, err
	}
	//Get Buyer Wallet address
	BuyerWalletAddress, error := GetWalletAddress(n)
	if error!=nil {
		return nil, "", 0, err
	}
	payment := datastructure.Payment{
		BuyerWalletAddress,
		VendorWalletAddress,
		totalItem,
		totalShipping,
		total,
	}
	shipping := datastructure.Shipping{
		contract.BuyerOrder.Shipping.ShipTo,
		contract.BuyerOrder.Shipping.Address,
		contract.BuyerOrder.Shipping.City,
		contract.BuyerOrder.Shipping.State,
		totalShipping,
		contract.BuyerOrder.Shipping.PostalCode,
		contract.BuyerOrder.Shipping.AddressNotes,
		"",
	}
	{
		fmt.Println("---------------------------------")
		fmt.Println(shipping.ShipTo)
		fmt.Println(shipping.Address)
		fmt.Println(shipping.City)
		fmt.Println(shipping.State)
		fmt.Println(shipping.PostalCode)
		fmt.Println(shipping.AddressNotes)
		fmt.Println("---------------------------------")
	}
	listings := new([]datastructure.Listing)
	for i:=0;i<len(contract.BuyerOrder.Items);i++  {
		item := contract.BuyerOrder.Items[i]
		listing, err := ParseContractForListing(item.ListingHash, contract)
		if err != nil {
			return nil, "", 0, err
		}
		customlisting := datastructure.Listing{
			data.Items[i].ListingHash,
			contract.VendorListings[i].Item.Images[0].Tiny,
			listing.Item.Price,
			item.Quantity,
			item.Memo,
		}
		*listings = append(*listings, customlisting)
	}
	other := new(datastructure.Other)
	other.CreateTime = strings.Split(time.Now().String(), ".")[0]
	other.AlternateContactInfo = data.AlternateContactInfo
	customOrder := datastructure.CustomOrder{
		orderId,
		n.IpfsNode.Identity.Pretty(),
		vendorID,
		payment,
		*listings,
		shipping,
		*other,
	}
	{
		fmt.Println("-----------这是打印customorder----------------------")
		fmt.Println(customOrder.ID)
		fmt.Println(customOrder.BuyerID)
		fmt.Println(customOrder.VendorID)
		fmt.Println(customOrder.Payment)
		fmt.Println(customOrder.Listings)
		fmt.Println(customOrder.Shipping)
		fmt.Println(customOrder.Other)
		fmt.Println("---------------------------------")
	}
	error = SendOrder(n, customOrder)
	if error!=nil {
		fmt.Println("SendOrder to contract error:%s", error.Error())
		//return nil, "", 0, err
	}
	return orderId, VendorWalletAddress, total,  nil
}

func createContractWithOrder(n core.OpenBazaarNode, data *core.PurchaseData) (*pb.RicardianContract, error) {
	contract := new(pb.RicardianContract)
	order := new(pb.Order)
	if data.RefundAddress != nil {
		order.RefundAddress = *(data.RefundAddress)
	} else {
		order.RefundAddress = n.Wallet.NewAddress(wallet.INTERNAL).EncodeAddress()
	}
	shipping := &pb.Order_Shipping{
		ShipTo:       data.ShipTo,
		Address:      data.Address,
		City:         data.City,
		State:        data.State,
		PostalCode:   data.PostalCode,
		Country:      pb.CountryCode(pb.CountryCode_value[data.CountryCode]),
		AddressNotes: data.AddressNotes,
	}
	order.Shipping = shipping

	id := new(pb.ID)
	profile, err := n.GetProfile()
	if err == nil {
		id.Handle = profile.Handle
	}

	id.PeerID = n.IpfsNode.Identity.Pretty()
	pubkey, err := n.IpfsNode.PrivateKey.GetPublic().Bytes()
	if err != nil {
		return nil, err
	}
	keys := new(pb.ID_Pubkeys)
	keys.Identity = pubkey
	ecPubKey, err := n.Wallet.MasterPublicKey().ECPubKey()
	if err != nil {
		return nil, err
	}
	keys.Bitcoin = ecPubKey.SerializeCompressed()
	id.Pubkeys = keys
	// Sign the PeerID with the Bitcoin key
	ecPrivKey, err := n.Wallet.MasterPrivateKey().ECPrivKey()
	if err != nil {
		return nil, err
	}
	sig, err := ecPrivKey.Sign([]byte(id.PeerID))
	id.BitcoinSig = sig.Serialize()
	order.BuyerID = id

	ts, err := ptypes.TimestampProto(time.Now())
	if err != nil {
		return nil, err
	}
	order.AlternateContactInfo = data.AlternateContactInfo

	var ratingKeys [][]byte
	for range data.Items {
		// FIXME: bug here. This should use a different key for each item. This code doesn't look like it will do that.
		// Also the fix for this will also need to be included in the rating signing code.
		ratingKey, err := n.Wallet.MasterPublicKey().Child(uint32(ts.Seconds))
		if err != nil {
			return nil, err
		}
		ecRatingKey, err := ratingKey.ECPubKey()
		if err != nil {
			return nil, err
		}
		ratingKeys = append(ratingKeys, ecRatingKey.SerializeCompressed())
	}
	order.RatingKeys = ratingKeys

	addedListings := make(map[string]*pb.Listing)
	for _, item := range data.Items {
		i := new(pb.Order_Item)

		/* It is possible that multiple items could refer to the same listing if the buyer is ordering
		   multiple items with different variants. If it is multiple items of the same variant they can just
		   use the quantity field. But different variants require two separate item entries. However,
		   in this case we do not need to add the listing to the contract twice. Just once is sufficient.
		   So let's check to see if that's the case here and handle it. */
		_, exists := addedListings[item.ListingHash]

		listing := new(pb.Listing)
		if !exists {
			// Let's fetch the listing, should be cached
			b, err := ipfs.Cat(n.Context, item.ListingHash)
			if err != nil {
				return nil, err
			}
			sl := new(pb.SignedListing)
			err = jsonpb.UnmarshalString(string(b), sl)
			if err != nil {
				return nil, err
			}
			contract.VendorListings = append(contract.VendorListings, sl.Listing)
			s := new(pb.Signature)
			s.Section = pb.Signature_LISTING
			s.SignatureBytes = sl.Signature
			contract.Signatures = append(contract.Signatures, s)
			addedListings[item.ListingHash] = sl.Listing
			listing = sl.Listing
		} else {
			listing = addedListings[item.ListingHash]
		}

		if strings.ToLower(listing.Metadata.AcceptedCurrencies[0]) != strings.ToLower(n.Wallet.CurrencyCode()) {
			return nil, fmt.Errorf("Contract only accepts %s, our wallet uses %s", listing.Metadata.AcceptedCurrencies[0], n.Wallet.CurrencyCode())
		}

		// Remove any duplicate coupons
		couponMap := make(map[string]bool)
		var coupons []string
		for _, c := range item.Coupons {
			if !couponMap[c] {
				couponMap[c] = true
				coupons = append(coupons, c)
			}
		}

		// Validate the selected options
		//listingOptions := make(map[string]*pb.Listing_Item_Option)
		//for _, opt := range listing.Item.Options {
		//	listingOptions[strings.ToLower(opt.Name)] = opt
		//}
		//for _, uopt := range item.Options {
		//	_, ok := listingOptions[strings.ToLower(uopt.Name)]
		//	if !ok {
		//		return nil, errors.New("Selected variant not in listing")
		//	}
		//	delete(listingOptions, strings.ToLower(uopt.Name))
		//}
		//if len(listingOptions) > 0 {
		//	return nil, errors.New("Not all options were selected")
		//}

		ser, err := proto.Marshal(listing)
		if err != nil {
			return nil, err
		}
		listingId, err := core.EncodeCID(ser)
		if err != nil {
			return nil, err
		}
		i.ListingHash = listingId.String()
		i.Quantity = uint32(item.Quantity)

		for _, option := range item.Options {
			o := &pb.Order_Item_Option{
				Name:  option.Name,
				Value: option.Value,
			}
			i.Options = append(i.Options, o)
		}
		so := &pb.Order_Item_ShippingOption{
			Name:    item.Shipping.Name,
			Service: item.Shipping.Service,
		}
		i.ShippingOption = so
		i.Memo = item.Memo
		i.CouponCodes = coupons
		order.Items = append(order.Items, i)
	}

	contract.BuyerOrder = order
	return contract, nil
}

func CalcOrderId(n *core.OpenBazaarNode, order *pb.Order) (*big.Int, error) {
	r := rand.Int63n(999999)
	time := time.Now().UnixNano()
	time = time%1514274100000000000
	time += r
	time = MurmurHash(time)
	if time < 0 {
		time = -time
	}
	bi := big.NewInt(time)
	return bi, nil
}

func MurmurHash(key int64) int64 {
	keyb := []byte(string(key))
	len := len(keyb)
	var m uint64
	var r, seed uint64
	m = 0x5bd1e995
	r = 24
	seed = 97
	h := seed ^ uint64(len)
	for ;key > 0; {
		k := uint64(key%10000)
		k *= m
		k ^= k >> r
		k *= m
		h *= m
		h ^= k
		key /= 10000
	}
	h ^= h >> 13
	h *= m
	h ^= h >> 15
	return int64(h)
}

func CalculateOrderTotal(n *(core.OpenBazaarNode), contract *pb.RicardianContract) (uint64, uint64, uint64, string, error) {
	var total uint64
	var totalItem uint64
	physicalGoods := make(map[string]*pb.Listing)
	BuyerWalletAddress := ""
	// Calculate the price of each item
	for _, item := range contract.BuyerOrder.Items {
		var itemTotal uint64
		l, err := ParseContractForListing(item.ListingHash, contract)
		if BuyerWalletAddress=="" {
			BuyerWalletAddress = l.TermsAndConditions
		}
		if err != nil {
			return 0,0,0,"", fmt.Errorf("Listing not found in contract for item %s", item.ListingHash)
		}
		if l.Metadata.ContractType == pb.Listing_Metadata_PHYSICAL_GOOD {
			physicalGoods[item.ListingHash] = l
		}
		itemTotal += l.Item.Price
		itemTotal *= uint64(item.Quantity)
		totalItem += itemTotal
	}
	total += totalItem

	var shippingTotal uint64
	for _, item := range contract.BuyerOrder.Items {
		listing, ok := physicalGoods[item.ListingHash]
		if !ok { // Not physical good no need to calculate shipping
			continue
		}
		var itemShipping uint64
		// Check selected option exists
		shippingOptions := make(map[string]*pb.Listing_ShippingOption)
		for _, so := range listing.ShippingOptions {
			shippingOptions[strings.ToLower(so.Name)] = so
		}
		option, ok := shippingOptions[strings.ToLower(item.ShippingOption.Name)]
		if !ok {
			return 0,0,0,"", errors.New("Shipping option not found in listing")
		}

		if option.Type == pb.Listing_ShippingOption_LOCAL_PICKUP {
			continue
		}

		// Check that this option ships to us
		regions := make(map[pb.CountryCode]bool)
		for _, country := range option.Regions {
			regions[country] = true
		}
		_, shipsToMe := regions[contract.BuyerOrder.Shipping.Country]
		_, shipsToAll := regions[pb.CountryCode_ALL]
		if !shipsToMe && !shipsToAll {
			return 0,0,0,"", errors.New("Listing does ship to selected country")
		}

		// Check service exists
		services := make(map[string]*pb.Listing_ShippingOption_Service)
		for _, shippingService := range option.Services {
			services[strings.ToLower(shippingService.Name)] = shippingService
		}
		service, ok := services[strings.ToLower(item.ShippingOption.Service)]
		if !ok {
			return 0,0,0,"", errors.New("Shipping service not found in listing")
		}
		shippingPrice := uint64(item.Quantity) * service.Price
		itemShipping += shippingPrice
		shippingTotal += itemShipping
	}
	total += shippingTotal
	fmt.Println("buyerwa:",BuyerWalletAddress)
	return total,totalItem, shippingTotal,BuyerWalletAddress, nil
}

func ParseContractForListing(hash string, contract *pb.RicardianContract) (*pb.Listing, error) {
	for _, listing := range contract.VendorListings {
		ser, err := proto.Marshal(listing)
		if err != nil {
			return nil, err
		}
		listingID, err := core.EncodeCID(ser)
		if err != nil {
			return nil, err
		}
		if hash == listingID.String() {
			return listing, nil
		}
	}
	return nil, errors.New("Not found")
}

func GetWalletAddress(n *core.OpenBazaarNode) (string, error) {
	address := ""
	address = incubator.GetWalletAddress()
	return address, nil
}

func GetPaymentAddress(PeerID string) (string, error) {
	address := ""
	address = incubator.GetWalletAddress()
	return address, nil
}

func SendOrder(n *core.OpenBazaarNode, order datastructure.CustomOrder) (error){
	//封装
	orderContract, error := order.ToOrderContract(n)
	if error != nil {
		fmt.Println(error.Error())
	}
	PrintOrder(*orderContract)

	//send合约
	var profile pb.Profile
	profile, error3 := n.GetProfile()
	if error3 != nil {
		fmt.Println("Failed to open profile: %v", error3)
		return error3
	}
	repoPath, error4 := repo.GetRepoPath(false)
	key, error4 := ioutil.ReadFile(path.Join(repoPath, "keystore", profile.Keypath))
	if error4 != nil {
		fmt.Println("%s", error4.Error())
	}
	var keydata string = string(key)
	auth, error5 := bind.NewTransactor(strings.NewReader(keydata),profile.Keywords)
	if error5 != nil {
		fmt.Println("%s", error5.Error())
	}

	orderToken, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("Call OrderContracts error 6:%s", error6.Error())
	}
	auth.Value = big.NewInt(orderContract.TotalPrice.Int64())
	auth.Value = auth.Value.Mul(auth.Value, big.NewInt(1000000))
	auth.Value = auth.Value.Mul(auth.Value, big.NewInt(1000000))
	auth.Value = auth.Value.Mul(auth.Value, big.NewInt(1000000))
	error7 := orderToken.TokenTransactor.CreatOrder(auth, *orderContract)
	if error7 != nil {
		fmt.Printf("orderToken.TokenTransactor.CreatOrder ERROR7 :%s\n", error7)
		return error7
	}

	//sendorder notification
	purchaseData, error := order.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, order.Other.CreateTime+datastructure.TimeTail)
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= order.ID.String()
	temp.RequestedAmount = order.Payment.Total
	temp.PaymentAddress = order.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", order.Other.CreateTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp

	error = n.SendOrder(order.VendorID,contract)
	if error != nil {
		fmt.Println("1", error.Error(), order.VendorID)
		return error
	}
	return nil
}

func PrintOrder(contract datastructure.OrderContract){
	fmt.Println("这是打印订单开始")
	fmt.Println("_id: ", contract.Id.String())
	fmt.Printf("_buyerId: %s\n", contract.BuyerId)
	fmt.Printf("_sellerId: %s\n", contract.SellerId)
	fmt.Printf("_buyer: %s\n", contract.Buyer.String())
	fmt.Printf("_seller: %s\n", contract.Seller.String())
	fmt.Println("_totalPrice: ", contract.TotalPrice.String())
	fmt.Printf("_goodJson: %s\n", contract.GoodJson)
	fmt.Printf("_shipJson: %s\n", contract.ShipJson)
	fmt.Printf("_otherJson: %s\n", contract.OtherJson)
	fmt.Printf("这是打印订单结束\n")
}

func QueryPurchase(n *core.OpenBazaarNode, orderStates []pb.OrderState, searchTerm string, sortByAscending, sortByRead bool, limit int) ([]repo.Purchase, int, error) {
	orderToken, error1 := contracts.CallOrderContract(contracts.Data)
	if error1 != nil {
		fmt.Println("%s", error1.Error())
	}

	IdsAsBuyer, error2 := orderToken.TokenCaller.GetIdsByBuyId(nil, n.IpfsNode.Identity.Pretty())
	if error2 != nil {
		fmt.Println("%s", error2.Error())
	}
	stateIF := new([13]bool)
	for _, item := range orderStates {
		stateIF[item] = true
	}
	purchases := new([]repo.Purchase)
	var index int = 0
	for  _, item := range IdsAsBuyer{
		order, state, error := orderToken.TokenCaller.GetOrderById(nil, item)
		if !stateIF[state] {
			continue
		}
		if error != nil {
			fmt.Println("1", error.Error())
			continue
		}
		customOrder, error := order.ToCustomOrder(n)
		if error != nil {
			fmt.Println("3", error.Error())
			continue
			//return nil, 0, error
		}
		purchase, error := customOrder.ToPurchase(n, state)
		if error != nil {
			fmt.Println("3", error.Error())
			continue
		}
		_,_,_,_,read,err :=n.Datastore.Purchases().GetByOrderId(order.Id.String())
		if err ==nil {
			purchase.Read = read
		}else {
			if error != nil {
				fmt.Println("%s", error.Error())
				return nil, 0, nil
			}
			purchaseData, error := customOrder.ToPurchaseData(n)
			if error != nil {
				fmt.Println("%s", error.Error())
				return nil, 0, nil
			}
			contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
			if error != nil {
				fmt.Println("%s", error.Error())
				return nil, 0, nil
			}
			//填写支付信息
			{
				payment := new(pb.Order_Payment)
				payment.Address = order.Seller.String()
				payment.Amount = customOrder.Payment.Total
				payment.Chaincode = ""
				payment.Method = pb.Order_Payment_DIRECT
				payment.Moderator = ""
				payment.ModeratorKey = *new([]byte)
				payment.RedeemScript = ""
				contract.BuyerOrder.Payment = payment
			}
			error = n.Datastore.Purchases().Put(order.Id.String(),*contract,0,false)
			if error != nil {
				fmt.Println("5", error.Error())
				continue
			}
		}
		if searchTerm!=""&&searchTerm!=purchase.Title&&searchTerm!=purchase.VendorId {
			break
		}
		*purchases = append(*purchases, *purchase)
		fmt.Println("查询purchase: ID:",purchase.OrderId,"state:",state)
		index++
	}
	return *purchases, index, nil
}

func QuerySales(n *core.OpenBazaarNode, orderStates []pb.OrderState, searchTerm string, sortByAscending, sortByRead bool, limit int) ([]repo.Sale, int, error) {
	orderToken, error1 := contracts.CallOrderContract(contracts.Data)
	if error1 != nil {
		fmt.Println("1 ", error1.Error())
	}
	IdsAsSeller, error2 := orderToken.TokenCaller.GetIdsBySellId(nil, n.IpfsNode.Identity.Pretty())
	if error2 != nil {
		fmt.Println("2 ", error2.Error())
	}
	stateIF := new([13]bool)
	for _, item := range orderStates {
		stateIF[item] = true
	}
	sales := new([]repo.Sale)
	var index int = 0
	for  _, item := range IdsAsSeller{
		if index >= limit {
			break
		}
		order, state, error := orderToken.TokenCaller.GetOrderById(nil, item)
		if !stateIF[state] {
			continue
		}
		if error != nil {
			fmt.Println("3 ", error.Error())
			continue
		}
		customOrder, error := order.ToCustomOrder(n)
		if error != nil {
			fmt.Println("4 ", error.Error())
			continue
		}
		sale, error := customOrder.ToSale(n, state)
		//

		_,_,_,_,read,err :=n.Datastore.Sales().GetByOrderId(order.Id.String())
		if err ==nil {
			sale.Read = read
		}else {
			if error != nil {
				fmt.Println("5 ", error.Error())
				continue
			}
			purchaseData, error := customOrder.ToPurchaseData(n)
			if error != nil {
				fmt.Println("6 ", error.Error())
				continue
			}
			contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
			if error != nil {
				fmt.Println("7 ", error.Error())
				continue
			}
			//填写支付信息
			{
				payment := new(pb.Order_Payment)
				payment.Address = order.Seller.String()
				payment.Amount = customOrder.Payment.Total
				payment.Chaincode = ""
				payment.Method = pb.Order_Payment_DIRECT
				payment.Moderator = ""
				payment.ModeratorKey = *new([]byte)
				payment.RedeemScript = ""
				contract.BuyerOrder.Payment = payment
			}
			error = n.Datastore.Sales().Put(order.Id.String(),*contract,0,false)
			if error != nil {
				fmt.Println("8 ", error.Error())
				continue
			}
		}

		if error != nil {
			fmt.Println("9 ", error.Error())
			continue
		}
		if searchTerm!=""&&searchTerm!=sale.Title&&searchTerm!=sale.BuyerId {
			break
		}
		*sales = append(*sales, *sale)
		fmt.Println("查询sale: ID:",sale.OrderId,"state:",state)
		index++
	}
	return *sales, index, nil
}

func GetOrder(n *core.OpenBazaarNode, Id string) (*pb.RicardianContract, pb.OrderState,  error) {
	orderToken, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return nil, 0, error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return nil, 0, error
	}
	order, state, error := orderToken.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return nil, 0, error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return nil, 0, error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	if error != nil {
		fmt.Println("%s", error.Error())
		return nil, 0, error
	}
	//填写支付信息
	{
		payment := new(pb.Order_Payment)
		payment.Address = order.Seller.String()
		payment.Amount = customOrder.Payment.Total
		payment.Chaincode = ""
		payment.Method = pb.Order_Payment_DIRECT
		payment.Moderator = ""
		payment.ModeratorKey = *new([]byte)
		payment.RedeemScript = ""
		contract.BuyerOrder.Payment = payment
	}
	//填写买家取消信息（Cancel）
	if customOrder.Other.CancelTime != "" {
		temp:=new(pb.Refund)
		temp.OrderID= customOrder.ID.String()
		timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", customOrder.Other.CancelTime+datastructure.TimeTail)
		temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
		contract.Refund = temp
	}
	//填写买家取消信息（Cancel）
	if pb.OrderState(state) == pb.OrderState_DECLINED {
		temp:=new(pb.Refund)
		temp.OrderID= customOrder.ID.String()
		timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", customOrder.Other.ConfirmTime+datastructure.TimeTail)
		temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
		contract.Refund = temp
	}
	//填写卖家确认信息（Accept or Reject）
	if customOrder.Other.ConfirmTime != "" {
		temp:=new(pb.OrderConfirmation)
		temp.OrderID= customOrder.ID.String()
		temp.RequestedAmount = customOrder.Payment.Total
		temp.PaymentAddress = customOrder.Payment.VendorAddress
		timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", customOrder.Other.ConfirmTime+datastructure.TimeTail)
		temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
		contract.VendorOrderConfirmation=temp
	}else {
		contract.VendorOrderConfirmation = nil
	}
	//填写发货信息
	if customOrder.Other.DeliveryTime != "" {
		temp1:=new([]*pb.OrderFulfillment)
		orderFulfil := new(pb.OrderFulfillment)
		orderFulfil.OrderId=customOrder.ID.String()
		orderFulfil.Slug= contract.VendorListings[0].Slug
		timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", customOrder.Other.DeliveryTime+datastructure.TimeTail)
		orderFulfil.Timestamp, _ = ptypes.TimestampProto(timestamp)
		*temp1 = append(*temp1, orderFulfil)

		temp2:=new([]*pb.OrderFulfillment_PhysicalDelivery)
		full_dlivery:=new(pb.OrderFulfillment_PhysicalDelivery)
		full_dlivery.TrackingNumber=customOrder.Shipping.ShipmentNumber
		full_dlivery.Shipper=" "
		*temp2=append(*temp2,full_dlivery)

		(*temp1)[0].PhysicalDelivery=*temp2
		contract.VendorOrderFulfillment=*temp1
	}
	if customOrder.Other.CompleteTime != "" {
		temp := new(pb.OrderCompletion)
		temp.OrderId=customOrder.ID.String()
		timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", customOrder.Other.CompleteTime+datastructure.TimeTail)
		temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
		contract.BuyerOrderCompletion=temp
	}


	return contract,pb.OrderState(int32(state)), nil
}

func CancelOrder(n *core.OpenBazaarNode, Id string) (error){
	orderTokenData, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	order, state, error := orderTokenData.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	var other = new(datastructure.Other)
	error = json.Unmarshal([]byte(order.OtherJson), other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	if pb.OrderState(int32(state)) != pb.OrderState_AWAITING_PICKUP && pb.OrderState(int32(state)) != pb.OrderState_AWAITING_FULFILLMENT{
		return errors.New("该订单已经被确认或取消")
	}

	other.CancelTime = strings.Split(time.Now().String(), ".")[0]

	otherJson, error := json.Marshal(other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	orderTokenTrade, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("%s", error6.Error())
	}

	auth, error := contracts.GetAuth(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	error7 := orderTokenTrade.TokenTransactor.CancelOrder(auth, big.NewInt(_id), string(otherJson))
	if error7 != nil {
		fmt.Printf("ERROR :%s\n", error7)
		return error7
	}

	//sendordercancel
	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= customOrder.ID.String()
	temp.RequestedAmount = customOrder.Payment.Total
	temp.PaymentAddress = customOrder.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", other.CancelTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp
	//k, err := crypto.UnmarshalPublicKey(contract.VendorListings[0].VendorID.Pubkeys.Identity)
	//if err != nil {
	//	fmt.Println("%s", error.Error())
	//	return error
	//}
	error = n.SendCancel(customOrder.VendorID, contract)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	return nil
}

func ConfirmOrder(n *core.OpenBazaarNode, Id string, Reject  bool) (error) {
	orderTokenData, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	order, state, error := orderTokenData.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	if pb.OrderState(int32(state)) != pb.OrderState_AWAITING_PICKUP {
		return errors.New("该订单已被确认")
	}
	var other = new(datastructure.Other)
	error = json.Unmarshal([]byte(order.OtherJson), other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	other.ConfirmTime = strings.Split(time.Now().String(), ".")[0]

	otherJson, error := json.Marshal(other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	orderTokenTrade, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("%s", error6.Error())
	}

	auth, error := contracts.GetAuth(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	//sendorderconfirmation
	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= customOrder.ID.String()
	temp.RequestedAmount = customOrder.Payment.Total
	temp.PaymentAddress = customOrder.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", other.ConfirmTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp
	if !Reject {
		error = orderTokenTrade.TokenTransactor.AcceptOrder(auth, big.NewInt(_id), string(otherJson))
		if error != nil {
			fmt.Println("%s", error.Error())
			return error
		}
		error = n.SendOrderConfirmation(customOrder.BuyerID, contract)
		if error != nil {
			fmt.Println("%s", error.Error())
			return error
		}
	}else {
		error = orderTokenTrade.TokenTransactor.RejectOrder(auth, big.NewInt(_id), string(otherJson))
		if error != nil {
			fmt.Println("%s", error.Error())
			return error
		}
		k, err := crypto.UnmarshalPublicKey(contract.BuyerOrder.BuyerID.Pubkeys.Identity)
		if err != nil {
			fmt.Println("%s", error.Error())
			return error
		}
		error = n.SendReject(customOrder.BuyerID, &k,contract)
		if error != nil {
			fmt.Println("%s", error.Error())
			return error
		}
	}
	if error != nil {
		fmt.Printf("ERROR :%s\n", error)
		return error
	}
	return nil
}

func FulfillOrder(n *core.OpenBazaarNode, Id string, shipmentNumber string) (error) {
	orderTokenData, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	order, state, error := orderTokenData.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	if pb.OrderState(int32(state)) != pb.OrderState_AWAITING_FULFILLMENT {
		return errors.New("该订单已发货")
	}
	var other = new(datastructure.Other)
	error = json.Unmarshal([]byte(order.OtherJson), other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	other.DeliveryTime = strings.Split(time.Now().String(), ".")[0]

	otherJson, error := json.Marshal(other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	var shipping = new(datastructure.Shipping)
	error = json.Unmarshal([]byte(order.ShipJson), shipping)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	shipping.ShipmentNumber = shipmentNumber

	shippingJson, error := json.Marshal(shipping)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	orderTokenTrade, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("%s", error6.Error())
		return error6
	}

	auth, error := contracts.GetAuth(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	error = orderTokenTrade.TokenTransactor.DeliveryConfirm(auth, big.NewInt(_id), string(shippingJson), string(otherJson))
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	//sendorderfulfillment

	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= customOrder.ID.String()
	temp.RequestedAmount = customOrder.Payment.Total
	temp.PaymentAddress = customOrder.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", other.DeliveryTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp
	k, err := crypto.UnmarshalPublicKey(contract.BuyerOrder.BuyerID.Pubkeys.Identity)
	if err != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	error = n.SendOrderFulfillment(customOrder.BuyerID,&k,contract)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	return nil
}

func CompleteOrder(n *core.OpenBazaarNode, Id string) (error){
	orderTokenData, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	order, state, error := orderTokenData.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	var other = new(datastructure.Other)
	error = json.Unmarshal([]byte(order.OtherJson), other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	if pb.OrderState(int32(state)) != pb.OrderState_FULFILLED {
		return errors.New("该订单已完成")
	}

	other.CompleteTime = strings.Split(time.Now().String(), ".")[0]

	otherJson, error := json.Marshal(other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	orderTokenTrade, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("%s", error6.Error())
	}

	auth, error := contracts.GetAuth(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	error7 := orderTokenTrade.TokenTransactor.ReceivedConfirm(auth, big.NewInt(_id), string(otherJson))
	if error7 != nil {
		fmt.Printf("ERROR :%s\n", error7)
		return error7
	}

	//sendcompletorder
	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= customOrder.ID.String()
	temp.RequestedAmount = customOrder.Payment.Total
	temp.PaymentAddress = customOrder.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", other.DeliveryTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp
	k, err := crypto.UnmarshalPublicKey(contract.VendorListings[0].VendorID.Pubkeys.Identity)
	if err != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	error = n.SendOrderCompletion(customOrder.VendorID,&k,contract)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	return nil
}

func RefundOrder(n *core.OpenBazaarNode, Id string) error{
	orderTokenData, error := contracts.CallOrderContract(contracts.Data)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	_id, error := strconv.ParseInt(Id, 10, 64)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	order, state, error := orderTokenData.TokenCaller.GetOrderById(nil, big.NewInt(_id))
	var other = new(datastructure.Other)
	error = json.Unmarshal([]byte(order.OtherJson), other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	if pb.OrderState(int32(state)) != pb.OrderState_AWAITING_FULFILLMENT{
		return errors.New("该订单已经取消")
	}

	other.CancelTime = strings.Split(time.Now().String(), ".")[0]

	otherJson, error := json.Marshal(other)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	orderTokenTrade, error6 := contracts.CallOrderContract(contracts.Trade)
	if error6 != nil {
		fmt.Println("%s", error6.Error())
	}

	auth, error := contracts.GetAuth(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}

	error7 := orderTokenTrade.TokenTransactor.CancelOrder(auth, big.NewInt(_id), string(otherJson))
	if error7 != nil {
		fmt.Printf("ERROR :%s\n", error7)
		return error7
	}
	//sendfund

	customOrder, error :=order.ToCustomOrder(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	purchaseData, error := customOrder.ToPurchaseData(n)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	contract, error := purchaseData.CreateContractWithOrder(n, customOrder.Other.CreateTime+datastructure.TimeTail)
	temp:=new(pb.OrderConfirmation)
	temp.OrderID= customOrder.ID.String()
	temp.RequestedAmount = customOrder.Payment.Total
	temp.PaymentAddress = customOrder.Payment.VendorAddress
	timestamp, _ := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", other.CompleteTime+datastructure.TimeTail)
	temp.Timestamp, _ = ptypes.TimestampProto(timestamp)
	contract.VendorOrderConfirmation=temp
	error = n.SendRefund(customOrder.BuyerID,contract)
	if error != nil {
		fmt.Println("%s", error.Error())
		return error
	}
	return nil
}
